#include "max31856.h"





void max31856_init(p_max31856 dev, uint8_t chan, SPI_HandleTypeDef *spix, GPIO_TypeDef *gpio_cs, uint16_t gpio_pin_cs, GPIO_PinState cs_valid)
{
    dev->chan = chan;

    dev->spix = spix;

    dev->gpio_cs = gpio_cs;
    dev->gpio_pin_cs = gpio_pin_cs;
    dev->cs_valid = cs_valid;
}

int max31856_write_reg(p_max31856 dev,uint8_t addr, uint8_t buffer[],uint8_t len) 
{
    int tmp;

    addr |= 0x80; // make sure top bit is set
    
    HAL_GPIO_WritePin(dev->gpio_cs, dev->gpio_pin_cs, dev->cs_valid);

    tmp = HAL_SPI_Transmit(dev->spix, &addr, 1, 1000);
    tmp = HAL_SPI_Transmit(dev->spix, buffer, len, 1000);

    HAL_GPIO_WritePin(dev->gpio_cs, dev->gpio_pin_cs, (GPIO_PinState)(!(dev->cs_valid)));
	
		return tmp;
}

int max31856_read_reg(p_max31856 dev,uint8_t addr, uint8_t buffer[],uint8_t len) 
{
    int tmp;

    addr &= 0x7F; // make sure top bit is not set

    HAL_GPIO_WritePin(dev->gpio_cs, dev->gpio_pin_cs, dev->cs_valid);

    tmp = HAL_SPI_Transmit(dev->spix, &addr, 1, 1000);
    tmp = HAL_SPI_Receive(dev->spix, buffer, len, 1000);

    HAL_GPIO_WritePin(dev->gpio_cs, dev->gpio_pin_cs, (GPIO_PinState)(!(dev->cs_valid)));
	
		return tmp;
}

uint32_t max31856_millis(p_max31856 dev)
{
  return HAL_GetTick();
}


/**************************************************************************/
/*!
    @brief  Set temperature conversion mode
    @param mode The conversion mode
*/
/**************************************************************************/
void max31856_set_conversion_mode(p_max31856 dev,max31856_conversion_mode_t mode) 
{
  dev->conversionMode = mode;
  
  uint8_t tem;

  max31856_read_reg(dev,MAX31856_CR0_REG,&tem,1);// get current register value

  if (dev->conversionMode == MAX31856_CONTINUOUS) {
    tem |= MAX31856_CR0_AUTOCONVERT; // turn on automatic
    tem &= ~MAX31856_CR0_1SHOT;      // turn off one-shot
  } 
  else 
  {
    tem &= ~MAX31856_CR0_AUTOCONVERT; // turn off automatic
    tem |= MAX31856_CR0_1SHOT;        // turn on one-shot
  }
  
  max31856_write_reg(dev,MAX31856_CR0_REG, &tem,1);// write value back to register
}

/**************************************************************************/
/*!
    @brief  Get temperature conversion mode
    @returns The conversion mode
*/
/**************************************************************************/
max31856_conversion_mode_t max31856_get_conversion_mode(p_max31856 dev) 
{
  return dev->conversionMode;
}

/**************************************************************************/
/*!
    @brief  Set which kind of Thermocouple (K, J, T, etc) to detect & decode
    @param type The enumeration type of the thermocouple
*/
/**************************************************************************/
void max31856_set_thermocouple_type(p_max31856 dev,max31856_thermocoupletype_t type) 
{
  uint8_t tem;

  max31856_read_reg(dev,MAX31856_CR1_REG,&tem,1);

  tem &= 0xF0; // mask off bottom 4 bits
  tem |= (uint8_t)type & 0x0F;

  max31856_write_reg(dev,MAX31856_CR1_REG, &tem,1);
}

/**************************************************************************/
/*!
    @brief  Get which kind of Thermocouple (K, J, T, etc) we are using
    @returns The enumeration type of the thermocouple
*/
/**************************************************************************/
max31856_thermocoupletype_t max31856_get_thermocouple_type(p_max31856 dev) 
{
  uint8_t tem;

  max31856_read_reg(dev,MAX31856_CR1_REG, &tem,1);
  tem &= 0x0F;

  return (max31856_thermocoupletype_t)(tem);
}
/**************************************************************************/
/*!
    @brief  Read the fault register (8 bits)
    @returns 8 bits of fault register data
*/
/**************************************************************************/
uint8_t max31856_read_fault(p_max31856 dev) 
{
  uint8_t tem;

  max31856_read_reg(dev,MAX31856_SR_REG, &tem,1);

  return tem;
}

/**************************************************************************/
/*!
    @brief  Sets the threshhold for internal chip temperature range
    for fault detection. NOT the thermocouple temperature range!
    @param  low Low (min) temperature, signed 8 bit so -128 to 127 degrees C
    @param  high High (max) temperature, signed 8 bit so -128 to 127 degrees C
*/
/**************************************************************************/
void max31856_set_cold_junction_fault_threshholds(p_max31856 dev,int8_t low, int8_t high) 
{
  uint8_t *tem;

  tem = (uint8_t*)&low;
  max31856_write_reg(dev,MAX31856_CJLF_REG, tem,1);

  tem = (uint8_t*)&high;
  max31856_write_reg(dev,MAX31856_CJHF_REG, tem,1);
}

/**************************************************************************/
/*!
    @brief  Sets the mains noise filter. Can be set to 50 or 60hz.
    Defaults to 60hz. You need to call this if you live in a 50hz country.
    @param  noiseFilter One of MAX31856_NOISE_FILTER_50HZ or
   MAX31856_NOISE_FILTER_60HZ
*/
/**************************************************************************/
void max31856_set_noise_filter(p_max31856 dev,max31856_noise_filter_t noiseFilter) 
{
  uint8_t tem;

  max31856_read_reg(dev,MAX31856_CR0_REG,&tem,1);// get current register value

  if (noiseFilter == MAX31856_NOISE_FILTER_50HZ) 
  {
    tem |= 0x01;
  } 
  else 
  {
    tem &= 0xfe;
  }

  max31856_write_reg(dev,MAX31856_CR0_REG, &tem,1);// write value back to register
}

/**************************************************************************/
/*!
    @brief  Sets the threshhold for thermocouple temperature range
    for fault detection. NOT the internal chip temperature range!
    @param  flow Low (min) temperature, floating point
    @param  fhigh High (max) temperature, floating point
*/
/**************************************************************************/
void max31856_set_temp_fault_threshholds(p_max31856 dev,float flow, float fhigh) 
{
  int16_t low, high;

  flow *= 16;
  low = flow;

  fhigh *= 16;
  high = fhigh;

  uint8_t tem;

  tem = high >> 8;
  max31856_write_reg(dev,MAX31856_LTHFTL_REG, &tem,1);
  tem = high;
  max31856_write_reg(dev,MAX31856_LTHFTL_REG, &tem,1);
  tem = low >> 8;
  max31856_write_reg(dev,MAX31856_LTHFTL_REG, &tem,1);
  tem = low;
  max31856_write_reg(dev,MAX31856_LTHFTL_REG, &tem,1);
}

/**************************************************************************/
/*!
    @brief  Begin a one-shot (read temperature only upon request) measurement.
    Value must be read later, not returned here!
*/
/**************************************************************************/
void max31856_trigger_one_shot(p_max31856 dev) 
{
  if (dev->conversionMode == MAX31856_CONTINUOUS)
    return;

  uint8_t tem;

  max31856_read_reg(dev,MAX31856_CR0_REG,&tem,1);// get current register value

  tem &= ~MAX31856_CR0_AUTOCONVERT;              // turn off autoconvert
  tem |= MAX31856_CR0_1SHOT;                     // turn on one-shot

  max31856_write_reg(dev,MAX31856_CR0_REG, &tem,1);// write value back to register
}

/**************************************************************************/
/*!
    @brief  Return status of temperature conversion.
    @returns true if conversion complete, otherwise false
*/
/**************************************************************************/
bool max31856_conversion_complete(p_max31856 dev) 
{
  if (dev->conversionMode == MAX31856_CONTINUOUS)
    return true;

  uint8_t tem;
  max31856_read_reg(dev,MAX31856_CR0_REG,&tem,1);

  return !(tem & MAX31856_CR0_1SHOT);
}

/**************************************************************************/
/*!
    @brief  Return cold-junction (internal chip) temperature
    @returns Floating point temperature in Celsius
*/
/**************************************************************************/
float max31856_read_CJ_temperature(p_max31856 dev) 
{
  uint8_t tmp[2];
  uint16_t tem1;
  max31856_read_reg(dev,MAX31856_CJTH_REG,tmp,2);

  return tem1 / 256.0;
}


/**************************************************************************/
/*!
    @brief  Return hot-junction (thermocouple) temperature
    @returns Floating point temperature in Celsius
*/
/**************************************************************************/
float max31856_read_thermocouple_temperature(p_max31856 dev) 
{
  // for one-shot, make it happen
  if (dev->conversionMode == MAX31856_ONESHOT) 
  {
    max31856_trigger_one_shot(dev);
    uint32_t start = max31856_millis(dev);
    while (!max31856_conversion_complete(dev)) 
    {
      if (max31856_millis(dev) - start > 250)
        return 0;
      HAL_Delay(10);
    }
  }
  // read the thermocouple temperature registers (3 bytes)
  uint8_t tmp[3];
  int32_t temp24;
  max31856_read_reg(dev,MAX31856_LTCBH_REG,tmp,3);
  temp24 = (tmp[0]<<16) | (tmp[1]<<8) | tmp[2];

  // and compute temperature
  if (temp24 & 0x800000) {
    temp24 |= 0xFF000000; // fix sign
  }

  temp24 >>= 5; // bottom 5 bits are unused

  return temp24 * 0.0078125;
}

/**************************************************************************/
/*!
    @brief  Initialize MAX31856 attach/set pins or SPI device, default to K
   thermocouple
    @returns Always returns true at this time (no known way of detecting chip
   ID)
*/
/**************************************************************************/
void max31856_setup(p_max31856 dev)
{
  uint8_t tem;
  // assert on any fault
  tem = 0x00;
  max31856_write_reg(dev,MAX31856_MASK_REG, &tem,1);

  // enable open circuit fault detection
  tem = MAX31856_CR0_OCFAULT0;
  max31856_write_reg(dev,MAX31856_CR0_REG, &tem,1);

  // set cold junction temperature offset to zero
  tem = 0x0;
  max31856_write_reg(dev,MAX31856_CJTO_REG, &tem,1);

  // set Type K by default
  max31856_set_thermocouple_type(dev,MAX31856_TCTYPE_K);

  // set One-Shot conversion mode
  max31856_set_conversion_mode(dev,MAX31856_ONESHOT);

}

 
void test_max31856_continuous(p_max31856 dev)
{
    //init
    {
    max31856_setup(dev);
    max31856_set_thermocouple_type(dev,MAX31856_TCTYPE_K);

    max31856_set_conversion_mode(dev,MAX31856_CONTINUOUS);
    }

    //loop
    {
    max31856_read_thermocouple_temperature(dev);
    }
}


void test_max31856_measurement(p_max31856 dev)
{
    //init
    {
    max31856_setup(dev);
    max31856_set_thermocouple_type(dev,MAX31856_TCTYPE_K);

    max31856_set_conversion_mode(dev,MAX31856_ONESHOT_NOWAIT);
    }

    //loop
    {
    max31856_trigger_one_shot(dev);

    HAL_Delay(500);

    if(max31856_conversion_complete(dev))
    {
      max31856_read_thermocouple_temperature(dev);
    }
   }
}


void test_max31856_oneshot(p_max31856 dev)
{
    //init
    {
    max31856_setup(dev);
    max31856_set_thermocouple_type(dev,MAX31856_TCTYPE_K);
    }
    
    //loop
    {
      max31856_read_CJ_temperature(dev);
      max31856_read_thermocouple_temperature(dev);
      
      max31856_read_fault(dev);

      HAL_Delay(1000);
    }

}



